import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTree;

import java.io.*;
import java.util.ArrayList;
import java.util.Random;

public class GenticProgram2 {
    public static int randomInt(int min,int max)
    {
        Random random = new Random();
        return random.nextInt(max)%(max-min+1) + min;
    }
    public static double randomDouble(int min,int max)
    {
        double r=Math.random();
        Random random = new Random();
        int randomInt = random.nextInt(max)%(max-min+1) + min;
        return randomInt+r;
    }
    public static  String readFromTextFile(String pathname) throws IOException {
        String code="";
        File filename = new File(pathname);
        InputStreamReader reader = new InputStreamReader(new FileInputStream(filename));
        BufferedReader br = new BufferedReader(reader);
        String line = "";
        line = br.readLine();
        while(line != null) {
            code+=line+"\n";
            line = br.readLine();
        }
        return code;
    }

    public static void getStateTree(Tree tree,ArrayList<Tree> statementTreeList)
    {
        TreeProcessor tp=new TreeProcessor();
        if(!tree.isEmpty()) {
            if (tree.getRootData().equals("statement"))
            {
                //System.out.println("statement");
                statementTreeList.add(tree);
            }

            if (tree.getChildCount() > 0) {

                for (int i = 0; i < tree.getChildCount(); i++) {
                    getStateTree(tree.getChild(i),statementTreeList);
                }
            }
        }

    }

    public static ArrayList<Tree> getStatementFromCpp(String loadPath) throws IOException {
        TreeProcessor tp=new TreeProcessor();
        String code=readFromTextFile(loadPath);

        ANTLRInputStream input = new ANTLRInputStream(code);
        CPP14Lexer lexer = new CPP14Lexer(input);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        CPP14Parser parser = new CPP14Parser(tokens);
        CPP14Parser.TranslationunitContext tree = parser.translationunit();

        tree.removeLastChild();
        Tree myTree=new Tree(tp.getRuleName(tree,parser));
        tp.convertTree(tree,parser,myTree);

        //findParamDecl(myTree);
        ArrayList<Tree> statementTreeList=new ArrayList<>();
        getStateTree(myTree,statementTreeList);
        printStatementTreeList(statementTreeList);
        return statementTreeList;


    }
    public static void printStatementTreeList(ArrayList<Tree> statementTreeList)
    {
        TreeProcessor tp=new TreeProcessor();
        for(int i=0;i<statementTreeList.size();i++)
        {
            Tree print=statementTreeList.get(i);
            System.out.print("statement "+i+" :");
            tp.printCode(print);
            System.out.println();
        }
    }
    public static ArrayList<Tree> getStatementFromDir(String dirPath) throws IOException {
        File f=new File(dirPath);
        ArrayList<Tree> statementTreeList=new ArrayList<>();
        if(f.isDirectory()) {
            File src = new File(f.toString() + "\\src");
            File[] srcs = src.listFiles();
            for (File s : srcs)
            {
                if (s.getPath().endsWith(".cpp"))
                {
                    System.out.println("File:"+s.getPath());
                    statementTreeList=getStatementFromCpp(s.getPath());

                }
            }
        }
        return statementTreeList;
    }
    public static void insertToStatementseq(Tree tree,Tree insertStatement) {
            Tree insert=insertStatement;
            tree.addNode(insert);
    }
    public static void insertStatementToStatementSeq(Tree tree,ArrayList<Tree> statementTreeList,double frac,int count)
    {


        if(!tree.isEmpty()) {
            if(tree.getRootData().equals("statementseq")&&tree.getChildCount()>=2&&randomDouble(0,1)<0.3){//find call function,make it return value

                for (int i = 0; i < statementTreeList.size(); i++) {
                    double r = randomDouble(0, 1);
                    if (r < frac) {
                        insertToStatementseq(tree, statementTreeList.get(i));
                        count--;
                    }
                }
            }
            if(count>0)
            {
                for (Tree child : tree.getChilds()) {
                    if (child != null) {
                        insertStatementToStatementSeq(child, statementTreeList, frac,count);

                    }
                }
            }
        }
    }
    public static void insertToFunc(Tree tree,ArrayList<Tree> statementTreeList,double funcFrac,double seqFrac,int count)
    {
        if(!tree.isEmpty()) {
            if(tree.getRootData().equals("functionbody")&&tree.getChildCount()==1){//find call function,make it return value
                double r = randomDouble(0,1);
                if(r<funcFrac) {
                    insertStatementToStatementSeq(tree, statementTreeList, seqFrac,count);
                }
            }
            for(Tree child : tree.getChilds()) {
                if(child != null) {
                    insertStatementToStatementSeq(child,statementTreeList,seqFrac,count);
                }
            }
        }
    }
    public static void insertToCpp(String loadPath,ArrayList<Tree> statementTreeList) throws IOException {
        TreeProcessor tp=new TreeProcessor();
        String code=readFromTextFile(loadPath);

        ANTLRInputStream input = new ANTLRInputStream(code);
        CPP14Lexer lexer = new CPP14Lexer(input);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        CPP14Parser parser = new CPP14Parser(tokens);
        CPP14Parser.TranslationunitContext tree = parser.translationunit();

        tree.removeLastChild();
        Tree myTree=new Tree(tp.getRuleName(tree,parser));
        tp.convertTree(tree,parser,myTree);

        //findParamDecl(myTree);
        insertToFunc(myTree,statementTreeList, 0.2,0.01,3);
        tp.printCode(myTree);
    }
    public static void insertToDir(String dirPath,ArrayList<Tree> statementTreeList) throws IOException {
        File f=new File(dirPath);
        if(f.isDirectory()) {
            File src = new File(f.toString() + "\\src");
            File[] srcs = src.listFiles();
            for (File s : srcs)
            {
                if (s.getPath().endsWith(".cpp"))
                {
                    System.out.println("File:"+s.getPath());
                    insertToCpp(s.getPath(),statementTreeList);

                }
            }
        }
    }
    public static void main(String[] args) throws IOException {
        //String loadPath="E:\\u\\home\\catkin_ws\\src\\navigation\\global_planner\\src\\planner_core.cpp";
        //getRosParamFromCpp(loadPath);
        //getRosParamFromDir("E:\\u\\home\\catkin_ws\\src\\navigation\\move_base");
        ArrayList<Tree> statementTreeList=new ArrayList<>();
        statementTreeList=getStatementFromDir("H:\\lib\\global_planner\\dstar");
        insertToDir("H:\\lib\\global_planner\\relaxed_astar",statementTreeList);

    }
}
